1 /* 2 Copyright: Marcelo S. N. Mancini (Hipreme|MrcSnm), 2018 - 2021 3 License: [https://creativecommons.org/licenses/by/4.0/|CC BY-4.0 License]. 4 Authors: Marcelo S. N. Mancini 5 6 Copyright Marcelo S. N. Mancini 2018 - 2021. 7 Distributed under the CC BY-4.0 License. 8 (See accompanying file LICENSE.txt or copy at 9 https://creativecommons.org/licenses/by/4.0/ 10 */ 11 module hip.util.time; 12 import core.stdc.time; 13 14 version(Windows) 15 { 16 import hip.util.windows; 17 extern(Windows) BOOL QueryPerformanceFrequency(LARGE_INTEGER* lpPerformanceCount) nothrow; 18 extern(Windows) BOOL QueryPerformanceCounter(LARGE_INTEGER* lpPerformanceCount) nothrow; 19 } 20 else version(PSVita) 21 { 22 extern(C) ulong get_psv_time() @nogc nothrow; 23 } 24 else version(WebAssembly) 25 { 26 extern(C) float monotimeNow() @nogc nothrow; 27 } 28 else 29 { 30 import core.stdc.config:c_long; 31 version(PSVita) 32 { 33 enum CLOCK_MONOTONIC = 4; 34 } 35 else 36 { 37 enum CLOCK_MONOTONIC = 1; 38 } 39 struct timespec 40 { 41 int tv_sec; //Seconds 42 c_long tv_nsec; //Nanoseconds 43 } 44 extern(C) int clock_gettime(int clock_id, timespec* tm) nothrow; 45 } 46 47 ulong getSystemTime() nothrow 48 { 49 version(Windows) 50 { 51 LARGE_INTEGER counter = void; 52 QueryPerformanceCounter(&counter); 53 return counter.QuadPart * 1_000_000_000; //Convert to nanos 54 } 55 else version(WebAssembly) 56 { 57 return cast(ulong)(monotimeNow() * 1_000_000); //ms to nano 58 } 59 else version(PSVita) 60 { 61 return get_psv_time() * 1_000; //MicroSeconds to Nano 62 } 63 else 64 { 65 timespec tm = void; 66 if(clock_gettime(CLOCK_MONOTONIC, &tm) != 0) 67 return 0; 68 return cast(size_t)(tm.tv_nsec + tm.tv_sec * 1e9); 69 } 70 } 71 private ulong getSystemTicksPerSecond() nothrow 72 { 73 version(Windows) 74 { 75 LARGE_INTEGER ticksPerSecond = void; 76 QueryPerformanceFrequency(&ticksPerSecond); 77 return ticksPerSecond.QuadPart; 78 } 79 else 80 { 81 return 0; 82 } 83 } 84 85 class HipTime 86 { 87 88 private __gshared ulong startTime; 89 private __gshared ulong ticksPerSecond; 90 protected __gshared long[string] performanceMeasurement; 91 92 static void initialize() 93 { 94 ticksPerSecond = getSystemTicksPerSecond(); 95 startTime = getSystemTime(); 96 } 97 98 static long getCurrentTime() nothrow 99 { 100 ulong time = 0; 101 version(Windows) 102 { 103 time = (getSystemTime() - startTime) / ticksPerSecond; 104 } 105 else 106 time = getSystemTime() - startTime; 107 return time; 108 } 109 static double getCurrentTimeDouble() nothrow 110 { 111 version(PSVita) 112 return Double(getCurrentTime()); 113 else 114 return cast(double)getCurrentTime(); 115 } 116 117 ///For some reason, float arithmetic is wrong on PSVita, so, use long instead... 118 static long getCurrentTimeAsMsLong() nothrow 119 { 120 return getCurrentTime() / 1_000_000; 121 } 122 123 static double getCurrentTimeAsMs() nothrow 124 { 125 return getCurrentTimeDouble() / 1_000_000.0f; 126 } 127 static double getCurrentTimeAsSeconds() nothrow 128 { 129 return getCurrentTimeDouble() / 1_000_000_000; 130 } 131 132 static void initPerformanceMeasurement(string name) 133 { 134 performanceMeasurement[name] = getCurrentTime(); 135 } 136 static void finishPerformanceMeasurement(string name) 137 { 138 // import std.stdio:writeln; 139 // writeln(name, " took ", (getCurrentTime() - performanceMeasurement[name])/1_000_000, "ms"); 140 } 141 142 static struct Profiler 143 { 144 private string name; 145 this(string name){this.name = name;HipTime.initPerformanceMeasurement(name);} 146 ~this(){HipTime.finishPerformanceMeasurement(name);} 147 } 148 static mixin template Profile(string name){mixin("HipTime.Profiler _profile"~name~" = HipTime.Profiler("~name~");");} 149 static mixin template ProfileFunction(){mixin("HipTime.Profiler _profileFunc = HipTime.Profiler(__PRETTY_FUNCTION__);");} 150 } 151 152 float seconds(float v){return v;} 153 float msecs(float v){return v*1_000;} 154 float usecs(float v){return v*1_000_000;} 155 float nsecs(float v){return v*1_000_000_000;}